package tcp

import (
	"bufio"
	"bytes"
	"com.zkh/agent/coap/utils"
	"context"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"log"
	"net"
	"time"

	"github.com/plgd-dev/go-coap/v3/message"
	"github.com/plgd-dev/go-coap/v3/message/codes"
	"github.com/plgd-dev/go-coap/v3/message/pool"
	"github.com/plgd-dev/go-coap/v3/tcp/coder"
)

// Client holds info about connection
type Client struct {
	id     string
	conn   net.Conn
	Server *Server
}

/* 测试数据
D29302A387B42E7379730464617461EB06E938343338333437383733344400000000FF5B7B227365727669636573223A5B7B22736964223A2276657273696F6E222C2264617461223A7B226F6E223A307D7D2C7B22736964223A22737769746368222C2264617461223A7B226F6E223A307D7D5D2C226465764964223A2262363366623432352D356236612D343539652D383536652D616338356465363633353066227D5D
*/
// Read client data from channel
func (c *Client) listen() {
	c.Server.onNewClient(c)
	reader := bufio.NewReader(c.conn)
	defer func() {
		c.Close()
	}()
	for {
		buf := make([]byte, dataMaxLen)
		len, err := reader.Read(buf)
		if err != nil {
			break
		}
		// buf, _ = hex.DecodeString(string(buf[:len]))
		coapBuffer := bytes.NewBuffer(buf[:len])
		for coapBuffer.Len() > 0 {
			var header coder.MessageHeader
			// 获取设备id信息,判断是否coap报文是否需要解密
			// 1.获取报文byte数组
			bufByte := coapBuffer.Bytes()
			log.Printf("Receive(From %v): %s\n", c.Conn().RemoteAddr(), hex.EncodeToString(bufByte))
			len, err = coder.DefaultCoder.DecodeHeader(bufByte, &header)
			// 获取消息头
			headerByte := bufByte[:len]
			payloadByte := bufByte[len:]
			// 获取options相关信息
			result, optionData, err := utils.ParseCoAPOptions(payloadByte)
			if err != nil {
				fmt.Printf("不能解析报文的options: %v\n", err)
				break
			}
			optionsByte := result.OptionsBytes
			// 获取设备id信息
			devId := optionData["DEV_ID"]
			path := optionData["URI-Path"]
			encryptMode, err := utils.GetEncryptMode(devId)
			if encryptMode == "plaintext" || path == "psk" || encryptMode == "" {

			} else {
				// 需要判断coap报文是否完整
				coapHeader := append(headerByte, optionsByte...)
				payLoad := result.PayloadBytes
				_, err := utils.CheckMac(devId, payLoad, coapHeader)
				if err != nil {
					fmt.Printf("不能校验报文的hmac: %v\n", err)
					break
				}
			}
			buffer := coapBuffer
			// 分割线
			if err != nil {
				log.Printf("listen error:%v\n", err)
				_, err = buffer.ReadByte()
				if err != nil {
					break
				}
			} else {
				log.Printf("header:%+v\n", header)
				ctx, cancel := context.WithTimeout(context.Background(), time.Second)
				defer cancel()
				req := pool.NewMessage(ctx)
				msgLen := int(header.MessageLength)
				if msgLen < 0 || msgLen > dataMaxLen-1 {
					fmt.Printf("MessageLength 越界: %v \n", msgLen)
					_, err = buffer.ReadByte()
					if err != nil {
						break
					}
					continue
				}
				_, err := req.UnmarshalWithDecoder(coder.DefaultCoder, buffer.Next(msgLen))
				if err != nil {
					fmt.Printf("cannot unmarshal with header: %v\n", err)
					_, err = buffer.ReadByte()
					if err != nil {
						break
					}
					continue
				}
				go func() {
					c.Server.OnNewMessage(c, req)
				}()
				// buffer = seekBufferToNextMessage(buffer, read)
			}
		}
	}
}

func seekBufferToNextMessage(buffer *bytes.Buffer, msgSize int) *bytes.Buffer {
	if msgSize == buffer.Len() {
		// buffer is empty so reset it
		buffer.Reset()
		return buffer
	}
	log.Printf("8888888888888888 %d - %d \n", msgSize, buffer.Len())
	// rewind to next message
	trimmed := 0
	for trimmed != msgSize {
		b := make([]byte, 4096)
		toRead := 4096
		if msgSize-trimmed < toRead {
			toRead = msgSize - trimmed
		}
		v, _ := buffer.Read(b[:toRead])
		trimmed += v
	}
	return buffer
}

// // Send text message to client
// func (c *Client) Send(message string) error {
// 	return c.SendBytes([]byte(message))
// }

func (c *Client) Response(devId string, path string, token message.Token, code codes.Code, contentFormat message.MediaType, d []byte, opts ...message.Option) error {

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	resp := pool.NewMessage(ctx)
	resp.ResetOptionsTo(opts)
	resp.SetPath(path)
	resp.SetToken(token)
	resp.SetCode(code)
	// 获取加密方式
	encryptMode, _ := utils.GetEncryptMode(devId)
	if encryptMode == "plaintext" || encryptMode == "" || path == "/.sys/psk" {
		// 不加密
		if d != nil {
			resp.SetContentFormat(contentFormat)
			resp.SetBody(bytes.NewReader(d))
		}
		reqBuf, err := resp.MarshalWithEncoder(coder.DefaultCoder)
		if err != nil {
			return err
		}
		log.Printf("Send(To %v): %s\n", c.Conn().RemoteAddr(), hex.EncodeToString(reqBuf))
		return c.SendBytes(reqBuf)
	} else if encryptMode == "AES-128-CBC" {
		// AES-128-CBC 加密
		mac, _ := GenerateMAC()
		// body数据加密
		bodyAES := utils.EncryptBodyAESCBC(devId, d)
		coapBody := append(bodyAES, mac...)
		if d != nil {
			resp.SetContentFormat(contentFormat)
			resp.SetBody(bytes.NewReader(coapBody))
		}
		reqBuf, err := resp.MarshalWithEncoder(coder.DefaultCoder)
		fmt.Printf("原报文的字符串: %s\n", hex.EncodeToString(reqBuf))

		header := coder.MessageHeader{}
		heaLen, err := coder.DefaultCoder.DecodeHeader(reqBuf, &header)
		headerByte := reqBuf[:heaLen]
		payloadByte := reqBuf[heaLen:]
		result, _, err := utils.ParseCoAPOptions(payloadByte)
		optionsByte := result.OptionsBytes
		coapHeader := append(headerByte, optionsByte...)
		// 对数据进行加密
		// 加密后的报文信息
		encryptData := utils.EncryptDataAESCBCMac(devId, d, coapHeader)

		fmt.Printf("加密后16进制报文字符串: %s\n", hex.EncodeToString(encryptData))

		// 测试生成报文的完整性和可用性
		// _, err = resp.UnmarshalWithDecoder(coder.DefaultCoder, encryptReqBuf)

		if err != nil {
			return err
		}
		log.Printf("Send(To %v): %s\n", c.Conn().RemoteAddr(), hex.EncodeToString(encryptData))
		return c.SendBytes(encryptData)
	} else {
		// AES-128-GCM 加密
		mac, _ := GenerateMAC()
		// body数据加密
		bodyAES := utils.EncryptBodyAESGCM(devId, d)
		coapBody := append(bodyAES, mac...)
		if d != nil {
			resp.SetContentFormat(contentFormat)
			resp.SetBody(bytes.NewReader(coapBody))
		}
		reqBuf, err := resp.MarshalWithEncoder(coder.DefaultCoder)
		fmt.Printf("原报文的字符串: %s\n", hex.EncodeToString(reqBuf))

		header := coder.MessageHeader{}
		heaLen, err := coder.DefaultCoder.DecodeHeader(reqBuf, &header)
		headerByte := reqBuf[:heaLen]
		payloadByte := reqBuf[heaLen:]
		result, _, err := utils.ParseCoAPOptions(payloadByte)
		optionsByte := result.OptionsBytes
		coapHeader := append(headerByte, optionsByte...)
		// 对数据进行加密
		// 加密后的报文信息
		encryptData := utils.EncryptDataAESGCMMac(devId, d, coapHeader)

		fmt.Printf("加密后16进制报文字符串: %s\n", hex.EncodeToString(encryptData))

		// 测试生成报文的完整性和可用性
		// _, err = resp.UnmarshalWithDecoder(coder.DefaultCoder, encryptReqBuf)

		if err != nil {
			return err
		}
		log.Printf("Send(To %v): %s\n", c.Conn().RemoteAddr(), hex.EncodeToString(encryptData))
		return c.SendBytes(encryptData)
	}

}

// GenerateMAC 获取随机32位mac
func GenerateMAC() ([]byte, error) {
	mac := make([]byte, 32)
	// 使用加密安全的随机数生成器填充32字节
	_, err := rand.Read(mac)
	if err != nil {
		return nil, fmt.Errorf("生成随机MAC失败: %v", err)
	}
	return mac, nil
}
func (c *Client) SendCoapMsg(devId string, path string, token message.Token, code codes.Code, contentFormat message.MediaType, d []byte, opts ...message.Option) error {

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	req := pool.NewMessage(ctx)
	req.ResetOptionsTo(opts)
	req.SetPath(path)
	req.SetToken(token)
	req.SetCode(code)
	// 获取加密方式
	encryptMode, _ := utils.GetEncryptMode(devId)
	if encryptMode == "plaintext" {
		// 不加密
		if d != nil {
			req.SetContentFormat(contentFormat)
			req.SetBody(bytes.NewReader(d))
		}
		reqBuf, err := req.MarshalWithEncoder(coder.DefaultCoder)
		if err != nil {
			return err
		}
		log.Printf("Send(To %v): %s\n", c.Conn().RemoteAddr(), hex.EncodeToString(reqBuf))
		return c.SendBytes(reqBuf)
	} else if encryptMode == "AES-128-CBC" {
		// AES-128-CBC 加密
		mac, _ := GenerateMAC()
		// body数据加密
		bodyAES := utils.EncryptBodyAESCBC(devId, d)
		coapBody := append(bodyAES, mac...)
		if d != nil {
			req.SetContentFormat(contentFormat)
			req.SetBody(bytes.NewReader(coapBody))
		}
		reqBuf, err := req.MarshalWithEncoder(coder.DefaultCoder)
		fmt.Printf("原报文的字符串: %s\n", hex.EncodeToString(reqBuf))

		// header := utils.MessageHeader{}
		// headerLen, err := utils.DecodeHeader(reqBuf, &header)
		header := coder.MessageHeader{}
		heaLen, err := coder.DefaultCoder.DecodeHeader(reqBuf, &header)
		headerByte := reqBuf[:heaLen]
		payloadByte := reqBuf[heaLen:]
		result, _, err := utils.ParseCoAPOptions(payloadByte)
		optionsByte := result.OptionsBytes
		coapHeader := append(headerByte, optionsByte...)
		// 对数据进行加密
		// 加密后的报文信息
		encryptData := utils.EncryptDataAESCBCMac(devId, d, coapHeader)

		fmt.Printf("加密后16进制报文字符串: %s\n", hex.EncodeToString(encryptData))

		// 测试生成报文的完整性和可用性
		// _, err = req.UnmarshalWithDecoder(coder.DefaultCoder, encryptReqBuf)

		if err != nil {
			return err
		}
		log.Printf("Send(To %v): %s\n", c.Conn().RemoteAddr(), hex.EncodeToString(encryptData))
		return c.SendBytes(encryptData)
	} else {
		// AES-128-GCM 加密
		mac, _ := GenerateMAC()
		// body数据加密
		bodyAES := utils.EncryptBodyAESGCM(devId, d)
		coapBody := append(bodyAES, mac...)
		if d != nil {
			req.SetContentFormat(contentFormat)
			req.SetBody(bytes.NewReader(coapBody))
		}
		reqBuf, err := req.MarshalWithEncoder(coder.DefaultCoder)
		fmt.Printf("原报文的字符串: %s\n", hex.EncodeToString(reqBuf))

		// header := utils.MessageHeader{}
		// headerLen, err := utils.DecodeHeader(reqBuf, &header)
		header := coder.MessageHeader{}
		heaLen, err := coder.DefaultCoder.DecodeHeader(reqBuf, &header)
		headerByte := reqBuf[:heaLen]
		payloadByte := reqBuf[heaLen:]
		result, _, err := utils.ParseCoAPOptions(payloadByte)
		optionsByte := result.OptionsBytes
		coapHeader := append(headerByte, optionsByte...)
		// 对数据进行加密
		// 加密后的报文信息
		encryptData := utils.EncryptDataAESGCMMac(devId, d, coapHeader)

		fmt.Printf("加密后16进制报文字符串: %s\n", hex.EncodeToString(encryptData))

		// 测试生成报文的完整性和可用性
		// _, err = req.UnmarshalWithDecoder(coder.DefaultCoder, encryptReqBuf)

		if err != nil {
			return err
		}
		log.Printf("Send(To %v): %s\n", c.Conn().RemoteAddr(), hex.EncodeToString(encryptData))
		return c.SendBytes(encryptData)
	}

}

// SendBytes Send bytes to client
func (c *Client) SendBytes(b []byte) error {
	_, err := c.conn.Write(b)
	if err != nil {
		c.Close()
	}
	return err
}

func (c *Client) SetId(id string) {
	c.id = id
}

func (c *Client) GetId() string {
	return c.id
}

func (c *Client) Conn() net.Conn {
	return c.conn
}

func (c *Client) Close() error {
	err := c.conn.Close()
	c.Server.onClientConnectionClosed(c, err)
	return err
}
